/**********************************************************************************************/
// dgt_BoolElement.h
//
// Common Lib for Digital Studio
// Block of management of bool functions
// Class of elementary part of bool function
//
// Copyright Diamant Group 2008
/**********************************************************************************************/
#include "dgtKernel.h"
#include "dgt_SmartMacros.h"
#include "dgt_Log.h"
#include "dgt_BoolElement.h"
#include "math.h"
#include <wx/arrimpl.cpp>

/**********************************************************************************************/
WX_DEFINE_OBJARRAY( BoolElementArray );

/**********************************************************************************************/
dgt_BoolElement::dgt_BoolElement()
: m_Operation( AND )
{
	START( "DgtKernel", "dgt_BoolElement::dgt_BoolElement" );

	RETURN_VOID( "dgt_BoolElement::dgt_BoolElement" );
}

/**********************************************************************************************/
BOOL_OPERATION	dgt_BoolElement::get_Operation( void )
{
	START( "DgtKernel", "dgt_BoolElement::get_Operation" );

	RETURN( "dgt_BoolElement::get_Operation", m_Operation );
	return m_Operation;
}

/**********************************************************************************************/
void dgt_BoolElement::set_Operation( BOOL_OPERATION inOperation )
{
	START( "DgtKernel", "dgt_BoolElement::set_Operation" );

	m_Operation = inOperation;

	RETURN_VOID( "dgt_BoolElement::set_Operation" )
}

/**********************************************************************************************/
wxArrayInt dgt_BoolElement::get_OpCodes( void )
{
	START( "DgtKernel", "dgt_BoolElement::get_OpCodes" );

	RETURN( "dgt_BoolElement::get_OpCodes", m_OpCodes );
	return m_OpCodes;
}

/**********************************************************************************************/
void dgt_BoolElement::set_OpCodes( wxArrayInt inArray )
{
	START( "DgtKernel", "dgt_BoolElement::set_OpCodes" );

	for( unsigned i = 0; i < inArray.Count(); i++ )
		m_OpCodes.Add( inArray.Item(i) );

	RETURN_VOID( "dgt_BoolElement::set_OpCodes" );
}

/**********************************************************************************************/
wxBoolArray dgt_BoolElement::get_Inverts( void )
{
	START( "DgtKernel", "dgt_BoolElement::get_Inverts" );

	RETURN( "dgt_BoolElement::get_Inverts", m_Inverts );
	return m_Inverts;
}

/**********************************************************************************************/
void dgt_BoolElement::set_Inverts( wxBoolArray inArray )
{
	START( "DgtKernel", "dgt_BoolElement::set_Inverts" );

	for( unsigned i = 0; i < inArray.Count(); i++ )
		m_Inverts.Add( inArray.Item(i) );

	RETURN_VOID( "dgt_BoolElement::set_Inverts" );
}

/**********************************************************************************************/
void dgt_BoolElement::AddNewOperand( int code, bool isInvert )
{
	START( "DgtKernel", "dgt_BoolElement::AddNewOperand" );
	LOG_PARAM( code );
	LOG_PARAM( isInvert );

	m_OpCodes.Add( code );
	m_Inverts.Add( isInvert );

	RETURN_VOID( "dgt_BoolElement::AddNewOperand" );
}

/**********************************************************************************************/
unsigned long dgt_BoolElement::Count( void )
{
	START( "DgtKernel", "dgt_BoolElement::Count" );
	
	unsigned long result = m_OpCodes.Count();

	RETURN( "dgt_BoolElement::Count", result  );
	return result;
}

/**********************************************************************************************/
dgt_BoolElement_Ptr dgt_BoolElement::IncreaseInputs( unsigned long inNewInputCount )
{
	START( "DgtKernel", "dgt_BoolElement::IncreaseInputs" );
	LOG_PARAM( inNewInputCount );

	dgt_BoolElement_Ptr result;
	result->set_Operation( m_Operation );
	
	// copying old values 

	unsigned i = 0;
	for( i = 0; i < m_OpCodes.Count(); i++ )
	{
		int code = m_OpCodes.Item( i );
		bool inv = m_Inverts.Item( i );
		
		result->AddNewOperand( code, inv );
	}

	int CodeToAdd = m_OpCodes.Item( i - 1 );
	bool InvToAdd = m_Inverts.Item( i - 1 );

	// Adding new
	for( unsigned j = i; j < inNewInputCount; j++ )
	{
		result->AddNewOperand( CodeToAdd, InvToAdd );
	}

	RETURN( "dgt_BoolElement::IncreaseInputs", result );
	return result;
}

/**********************************************************************************************/
BoolElementArray dgt_BoolElement::ReduceInputs( unsigned long inNewInputCount )
{
	START( "DgtKernel", "dgt_BoolElement::ReduceInputs" );
	LOG_PARAM( inNewInputCount );

	unsigned long count = Count();

	BoolElementArray result;
	unsigned rCount = (unsigned) ceil ( (double) ( count / inNewInputCount ) );			// Count of elements in result

	// creating elements
	for( unsigned i = 0; i < rCount; i++ )
	{
		dgt_BoolElement_Ptr tElement( new dgt_BoolElement() );
		tElement->set_Operation( m_Operation );

		unsigned long t_c = ( i * inNewInputCount );
		for( unsigned j = t_c; j < (t_c + inNewInputCount); j++ )
		{
			bool tInv;
			int tCode;

			if( j < count )
			{
				tInv = m_Inverts.Item( j );
				tCode = m_OpCodes.Item( j );
			}
			else
			{
				tInv = m_Inverts.Item( count - 1 );
				tCode = m_OpCodes.Item( count - 1 );
			}
			tElement->AddNewOperand( tCode, tInv );
		}
		result.Add( tElement );
	}

	RETURN( "dgt_BoolElement::ReduceInputs", result );
	return result;
}


/**********************************************************************************************/
BoolElementArray MergeElements( BoolElementArray	inArray, 
								unsigned			inLimit,
								bool				isGenInvert )
{
	START( "DgtKernel", "MergeElements" );
	LOG_PARAM( inArray );
	LOG_PARAM( inLimit );
	LOG_PARAM( isGenInvert );

	BoolElementArray result;

	BOOL_OPERATION t_Op = inArray.Item(0)->get_Operation();

	// At first adding base elements
	for( unsigned i = 0; i < inArray.Count(); i++ )
	{
		dgt_BoolElement_Ptr tElement( new dgt_BoolElement() );
		tElement = inArray.Item( i );

		result.Add( tElement );
	}

	// Forming general union
	unsigned n = 0, i;	
	bool finish;
	unsigned tCount = result.Count();
	do 
	{
		finish = false;

		dgt_BoolElement_Ptr tElement( new dgt_BoolElement() );

		for( i = n; i < (n + inLimit); i++ )
		{
			if( i > tCount )
			{
				tElement->AddNewOperand( -tCount, isGenInvert );
				finish = true;
			}
			else
			{
				tElement->AddNewOperand( -(i+1), isGenInvert );
			}
		}
		n = i;
		result.Add( tElement );
	} 
	while(!finish);

	RETURN( "MergeElements", result );
	return result;
}

/**********************************************************************************************/
unsigned get_FirstLevelCount( BoolElementArray inArray )
{
	START( "DgtKernel", "get_FirstLevelCount" );
	LOG_PARAM( inArray )

	unsigned result = 0;

	for( unsigned i = 0; i < inArray.Count(); i++ )
	{
		dgt_BoolElement_Ptr tElement( new dgt_BoolElement() );
		tElement = inArray.Item( i );

		bool flag = false;

		wxArrayInt op = tElement->get_OpCodes();
		for( unsigned j = 0; j < op.Count(); j++ )
		{
			int t_code = op.Item( j );
			if( t_code < 0 )		// This is not first level already
			{
				flag = true;
				break;
			}
		}
		if( !flag )
			result++;
		else
			break;
	}

	RETURN( "get_FirstLevelCount", result );
	return result;
}